package com.example.demo.common;


import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.UUID;

/**
 *  密码工具类
 *  加盐加密/ 解密
 *
 *  之后需要在 注册 和 登录 接口中修改
 */
public class PasswordTools {


    /**
     * 加盐加密  encrypt:加密
     * @param password 明文密码
     * @return 加盐加密的密码.返回结果 65位
     * 方便调用用 static
     */
    public static String encrypt(String password) {
        // 1.产生盐值,使用 uuid，全球唯一，32位的
        //   中间有 - ，我们把 - 给去掉
        String salt = UUID.randomUUID().toString().replace("-","");

        // 2.使用盐值 + 明文密码，得到加密的密码，用 md5 的加密算法（不可逆）,
        //   使用别的算法也可以，只要使用相同的方式去验证就行
        //   md5 在spring 中有一个类 DigestUtils,md5DigestAsHex 转换成16进制,最后加密之后的密码就是一个16进制 32位的数字
        String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes(StandardCharsets.UTF_8));

        // 3.将盐值 和 加密的密码共同返回，合并盐值和密码（要将盐值也返回回去，否则没法校验密码是否正确）
        //   此处的 $ 只是为了区分盐值 和 加密之后的密码，用 " " 或者 | 都可以
        //   最后的位数是 32 + 1 + 32 = 65
        String dbPassword = salt + "$" + finalPassword;
        return dbPassword;
    }


    /**
     * 方法重载
     * 加盐加密  encrypt:加密
     * @param password 明文密码
     * @return    salt: 给定特定的盐值,不让他随机生成
     * 方便调用用 static
     */
    public static String encrypt(String password,String salt) {
        // 1.产生盐值,使用 uuid，全球唯一，32位的
        //   中间有 - ，我们把 - 给去掉
        //String salt = UUID.randomUUID().toString().replace("-","");

        // 2.使用盐值 + 明文密码，得到加密的密码，用 md5 的加密算法（不可逆）,
        //   使用别的算法也可以，只要使用相同的方式去验证就行
        //   md5 在spring 中有一个类 DigestUtils,md5DigestAsHex 转换成16进制,最后加密之后的密码就是一个16进制 32位的数字
        //String finalPassword1 = DigestUtils.md5DigestAsHex((salt + password).getBytes(StandardCharsets.UTF_8));
        String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes(StandardCharsets.UTF_8));
        // 3.将盐值 和 加密的密码共同返回，合并盐值和密码（要将盐值也返回回去，否则没法校验密码是否正确）
        //   此处的 $ 只是为了区分盐值 和 加密之后的密码，用 " " 或者 | 都可以
        //   最后的位数是 32 + 1 + 32 = 65
        String dbPassword = salt + "$" + finalPassword;
        return dbPassword;
    }

    /**
     * 验证加盐加密密码
     * @param password 明文密码（不一定对，需要验证明文密码）
     * @param dbPassword 数据库存储的密码（包含 salt + $ + 加盐加密之后的密码）
     * @return true = 密码正确
     */
    public static boolean decrypt(String password, String dbPassword) {
        boolean result = false;
        // 非空校验
        if(StringUtils.hasLength(password) && StringUtils.hasLength(dbPassword)
                // 校验加密之后密码的格式
                && dbPassword.length() == 65 && dbPassword.contains("$")) {
            // 1.得到盐值,dbPassword 的前32位就是盐值，我们自己规定的
            //   注意 $ 是有特殊的含义，需要用 \ 进行转义，而\ 也是有特殊的含义，所以\也需要转义
            String[] passwordArr = dbPassword.split("\\$");
            // 1.1 盐值
            String salt = passwordArr[0];
//            // 1.2 得到正确密码的加盐加密密码
//            String finalPassword = passwordArr[1];
            // 2.生成验证密码的加盐加密密码
            String checkPassword = encrypt(password,salt);
            if(checkPassword.equals(dbPassword)) {
                result = true;
            }
        }
        return result;
    }


    /**
     * 测试用的
     * @param args
     */
    public static void main(String[] args) {
        String password = "123";

        String pw1 = encrypt(password);
        String pw2 = encrypt(password);
        String pw3 = encrypt(password);

        System.out.println(pw1);
        System.out.println(pw2);
        System.out.println(pw3);


        String cPwd = "123456";
        // 大写是包装类
        boolean result = decrypt(cPwd,pw1);
        System.out.println("错误结果： " + result);


        result = decrypt(password,pw2);
        System.out.println("正确结果： " + result);
//        System.out.println(encrypt(""));
    }
}
